#include "debug_serial.h"

void debug_port_init(uint32_t baudrate)
{
  gpio_init_type gpio_init_struct;

  /* enable the uart and gpio clock */
  crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  gpio_default_para_init(&gpio_init_struct);
  /* configure the uart tx pin */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_pins = GPIO_PINS_2;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init(GPIOA, &gpio_init_struct);

  /* configure uart param */
  usart_init(USART2, baudrate, USART_DATA_8BITS, USART_STOP_1_BIT);
  usart_transmitter_enable(USART2, TRUE);
  usart_dma_transmitter_enable(USART2, TRUE);
  usart_enable(USART2, TRUE);

  dma_init_type dma_init_struct;
  /* enable dma1 clock */
  crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
  /* dma1 channel1 for usart2 tx configuration */
  dma_reset(DMA1_CHANNEL1);
  dma_default_para_init(&dma_init_struct);
  dma_init_struct.buffer_size = 0;
  dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
  dma_init_struct.memory_base_addr = (uint32_t)NULL;
  dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
  dma_init_struct.memory_inc_enable = TRUE;
  dma_init_struct.peripheral_base_addr = (uint32_t)&USART2->dt;
  dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
  dma_init_struct.peripheral_inc_enable = FALSE;
  dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
  dma_init_struct.loop_mode_enable = FALSE;
  dma_init(DMA1_CHANNEL1, &dma_init_struct);

  /* config flexible dma for usart2 tx */
  dma_flexible_config(DMA1, FLEX_CHANNEL1, DMA_FLEXIBLE_UART2_TX);
}

void debug_port_write(uint8_t* dat, uint16_t count)
{
  DMA1_CHANNEL1->dtcnt = count;
  DMA1_CHANNEL1->maddr = (uint32_t)dat;
  dma_channel_enable(DMA1_CHANNEL1, TRUE);
  while(dma_flag_get(DMA1_FDT1_FLAG) == RESET)
  {
  }
  while(usart_flag_get(USART2, USART_TDC_FLAG) == RESET);
  dma_channel_enable(DMA1_CHANNEL1, FALSE);
}

void debug_port_write_hex(uint8_t* data, uint16_t count)
{
  // USE JUSTFLOAT https://www.vofa.plus/plugin_detail/?name=justfloat
  static uint8_t tail[4] = {0x00, 0x00, 0x80, 0x7f};
  debug_port_write(data, count);
  debug_port_write(tail, 4);
}

static char buffer[80];
int debug_printf(char* format, ...)
{
  int ret;
  va_list aptr;

  va_start(aptr, format);
  ret = vsprintf(buffer, format, aptr);
  va_end(aptr);

  debug_port_write((uint8_t*)buffer, ret <= 80 ? ret : 80);

  return(ret);
}